package com.yuzhi.master.sewage.device.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuzhi.common.core.domain.entity.SysUser;
import com.yuzhi.common.enums.NoticeMsgValEnum;
import com.yuzhi.master.conBjMx.domain.bo.ConBjMxBo;
import com.yuzhi.master.conBjMx.domain.vo.ConBjMxVo;
import com.yuzhi.master.conBjMx.service.IConBjMxService;
import com.yuzhi.master.drainAlarmRule.domain.request.DrainAlarmRuleReq;
import com.yuzhi.master.drainAlarmRule.domain.vo.DrainAlarmRuleVo;
import com.yuzhi.master.drainAlarmRule.service.IDrainAlarmRuleService;
import com.yuzhi.master.drainMsgNotice.domain.DrainMsgNotice;
import com.yuzhi.master.drainMsgNotice.domain.bo.DrainMsgNoticeBo;
import com.yuzhi.master.drainMsgNotice.service.IDrainMsgNoticeService;
import com.yuzhi.master.drainRRmst.domain.DrainRRmst;
import com.yuzhi.master.drainRRmst.domain.vo.DrainRRmstVo;
import com.yuzhi.master.drainRRmst.mapper.IDraRRmstMapper;
import com.yuzhi.master.drainSms.service.IDrainSmsInfoService;
import com.yuzhi.master.sewage.device.domain.DrainDeviceZt;
import com.yuzhi.master.sewage.device.domain.vo.DrainDeviceZtVo;
import com.yuzhi.master.sewage.device.mapper.DrainDeviceZtMapper;
import com.yuzhi.master.sewage.device.service.IDrainDeviceZtService;
import com.yuzhi.master.sewage.rmstSz.service.IAlarmRuleProcessor;
import com.yuzhi.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 设备实时状态数据采集表 drain_device_zt
 */
@RequiredArgsConstructor
@Service
public class DrainDeviceZtServiceImpl extends ServiceImpl<DrainDeviceZtMapper, DrainDeviceZt> implements IDrainDeviceZtService  {

    private final DrainDeviceZtMapper drainDeviceZtMapper;
    private final IDraRRmstMapper draRRmstMapper;
    private final IDrainAlarmRuleService drainAlarmRuleService;
    private final IConBjMxService  cnBjMxService;
    private final ISysUserService userService;
    private final IDrainMsgNoticeService drainMsgNoticeService;
    private final IConBjMxService iConBjMxService;
    private final IAlarmRuleProcessor  alarmRuleProcessor;
    private final IDrainSmsInfoService drainSmsInfoService;

    /**
     * mqtt同步物联网设置实时状态数据
     * @param mgttStr
     */
    @Override
   public void saveDeviceZtByMqtt(String mgttStr,DrainRRmstVo drainRRmstVo)
   {
       try
       {
           StringBuffer  sf  = new StringBuffer("");
           JSONObject jsonObject = JSONObject.parseObject(mgttStr);

           DrainDeviceZt  deviceZt  = new DrainDeviceZt();

           //设备ID
           String deviceId  =  jsonObject.getString("deviceId");
           // 测站设备编号
           deviceZt.setFkId(drainRRmstVo.getStcd());
           // 设备类型
           deviceZt.setFkType(4);
           //设备状态(上线:1，下线:0)
           if(jsonObject.getInteger("eventType") != null)
           {
               deviceZt.setState(jsonObject.getInteger("eventType").toString());
           }
           //采集时间
           Long cjTime = jsonObject.getLong("timestamp");
           if(cjTime!=null)
           {
               // 格式化输出
               Instant instant = Instant.ofEpochMilli(cjTime);
               LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
               deviceZt.setCjTime(dateTime);
           }
           // 1、新增mgtt设备状态消息
           drainDeviceZtMapper.insert(deviceZt);
           sf.append("新增mgtt设备状态消息>>>>"+deviceId).append(",设备状态:"+deviceZt.getState());

           // 2、更新设备实时状态
           if(deviceId != null)
           {
              int updateSize = draRRmstMapper.update(null,
                       new LambdaUpdateWrapper<DrainRRmst>()
                               .eq(DrainRRmst::getId, deviceId)
                               .set(DrainRRmst::getIsOnline, deviceZt.getState()))  ;
               sf.append("，更新设备实时状态记录数>>>>"+updateSize);
           }

           // 3、是否新增离线告警
           if("0".equals(deviceZt.getState()) ) //设备离线
           {
               DrainAlarmRuleReq request  = new DrainAlarmRuleReq();
               request.setAlarmType("1");  //查询设备离线告警配置
               request.setFacilityType("4");//离线告警 污水管网
               List<DrainAlarmRuleVo>  ruleVoList  =  drainAlarmRuleService.queryDrainAlarmRule(request);
               if(ruleVoList!=null && !ruleVoList.isEmpty()) //存在告警规则  需要告警
               {
                   DrainAlarmRuleVo  ruleVo  = ruleVoList.get(0);
                   //  检查是否满足新增入库告警条件
                   boolean flagRule =  checkDrainAlarmRule(deviceId, ruleVo);
                   if(flagRule)
                   {
                       //3、新增告警记录并转工单
                       boolean  addFlag  = addConBjMxBo(deviceZt, drainRRmstVo, ruleVo);
                       sf.append("，新增设备离线告警记录>>>>"+addFlag);

                       //4、新增异常告警消息通知
                       List<String> noticeUserIdList =  addDrainMsgNotice(  deviceZt, drainRRmstVo,  ruleVo);
                       sf.append("，新增设备离线告警通知消息人员ID>>>>"+noticeUserIdList.toString());
                   }else
                   {
                       sf.append("，不满足告警入库规则>>>>");
                   }

               }

           }
           else if("1".equals(deviceZt.getState()) ) //设备在线
           {
               // 更新设备离线告警结束时间、告警处置状态
               Boolean  onlineFlag =  iConBjMxService.updateOnlineConBjMx(deviceId);
               log.error(">>>>>>设备在线更新状态>>>"+onlineFlag);
           }

           log.error(sf.toString());
       }
       catch (Exception e) {
           log.error("保存设备实时状态数据失败", e);
       }


   }

    /**
     * 新增告警记录并转工单
     * @param deviceZt
     * @param drainRRmstVo
     * @param ruleVo
     * @return
     */
    private boolean addConBjMxBo(DrainDeviceZt  deviceZt,DrainRRmstVo drainRRmstVo,DrainAlarmRuleVo  ruleVo)
    {
        ConBjMxBo bo = new ConBjMxBo();
        bo.setFKey(deviceZt.getFkId());
        if ("2".equals(drainRRmstVo.getSttp())) {
            //流量设备数据处理
            bo.setFKeyType(6);
        }
        if ("1".equals(drainRRmstVo.getSttp())) {
            //水质设备数据处理
            bo.setFKeyType(3);
        }
        bo.setCbDesc(drainRRmstVo.getStnm()+"离线，请尽快处理!");
        bo.setCbTime(deviceZt.getCjTime());
        if(drainRRmstVo.getStLong()!=null && drainRRmstVo.getStLat()!=null)
        {
            bo.setDLg(drainRRmstVo.getStLong()+","+drainRRmstVo.getStLat());  //设备位置
        }
        // 报警类型（1离线报警/2液位异常/3水质检测报警/4流量超标）
        bo.setBjType("1");
        // 报警设备名称
        bo.setFKeyName(drainRRmstVo.getStnm());
        // 报警规则ID
        bo.setAlarmRuleId(ruleVo.getId());
        // 是否转工单
        bo.setTransferWork(ruleVo.getTransferWork());
        if(ruleVo.getTransferWork())  //是-需要转工单
        {
            bo.setIsCl("2");  //   是否处理状态(0：待受理，1：需处理，2：处理中，3：已处理，4：无需处理)
        }else {
            bo.setIsCl("1");  //   是否处理状态(0：待受理，1：需处理，2：处理中，3：已处理，4：无需处理)
        }

        //新增告警记录并转工单
        boolean flag = cnBjMxService.conBjTransferWork(bo,ruleVo);

        return flag;
    }

    /**
     * 按照设备状态统计
     * @return
     */
    @Override
    public  Map<String, Long> countDevicesByStatus()
    {
        // 查询设备最新状态
        List<DrainDeviceZtVo> ztList  =  drainDeviceZtMapper.countDevicesByStatus();

        Map<String, Long> stateCounts = ztList.stream()
                .collect(Collectors.groupingBy(
                        DrainDeviceZtVo::getState,  // 按state分组
                        Collectors.counting()       // 统计每组数量
                ));

        Map<String, Long>  statusMap  = new HashMap<>();

        stateCounts.forEach((state, count) -> {
            // 状态 0下线，1上线
            if("0".equals(state))
            {
                statusMap.put("offLine",count);

            }
            else if("1".equals(state))
            {
                statusMap.put("onLine",count);
            }

        });

        return  statusMap;
    }

    /**
     * 检查是否满足告警规则入库告警记录
     * @return
     */
    private boolean checkDrainAlarmRule(String fKey, DrainAlarmRuleVo alarmRule)
    {
        //查询记录表数据是否大于规则时间
        ConBjMxBo bjMxBo = new ConBjMxBo();
        bjMxBo.setFKey(fKey);
        // 报警类型（1离线报警/2液位异常/3水质检测报警/4流量超标）
        bjMxBo.setBjType("1");
        List<ConBjMxVo> conBjMxVoList = iConBjMxService.getfFeyId(bjMxBo);

        // 根据规则的 interval_value/interval_unit 判断是否允许新增
        boolean allowedByInterval =  alarmRuleProcessor.shouldInsertByInterval(conBjMxVoList, alarmRule);

        return  allowedByInterval;
    }

    /**
     * 推送告警通知消息
     * @param deviceZt
     * @param drainRRmstVo
     * @param ruleVo
     * @return 通知人员
     */
    private List<String>  addDrainMsgNotice(DrainDeviceZt  deviceZt,DrainRRmstVo drainRRmstVo,DrainAlarmRuleVo  ruleVo)
    {
        List<String>  userIdList = new ArrayList<>();

        //告警规则消息推送人
        String receiverUserIds  = ruleVo.getReceiverIds();
        if(receiverUserIds!=null && StringUtils.isNotBlank(receiverUserIds))
        {
            // 所有用户ID集合
            List<String> allUserIds = Arrays.stream(receiverUserIds.split(","))
                    .map(String::trim)
                    .filter(id -> !id.isEmpty())
                    .distinct()
                    .collect(Collectors.toList());

            List<SysUser>  sysUserList =  userService.selectUserByIds(allUserIds) ;

            // 4、推送消息通知
            for(SysUser sysUser : sysUserList)
            {
                Map<String,String>  paramMap  = new HashMap<>();
                paramMap.put(NoticeMsgValEnum.ALARM_DEVICE_NAME.getMsgType(),drainRRmstVo.getStnm());  //告警设备名称
                if(deviceZt.getCjTime() != null )
                {
                    DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    paramMap.put(NoticeMsgValEnum.ALARM_TIME.getMsgType(), deviceZt.getCjTime().format(formatter2));
                }

                DrainMsgNoticeBo noticeBo = new DrainMsgNoticeBo();
                noticeBo.setNoticeUser(sysUser.getId());
                noticeBo.setNoticeUserName(sysUser.getNickName());
                noticeBo.setFkType("5");  //外键类型(1、巡检 2、事件 3、催办 4、告警、5、设备离线)
                noticeBo.setFkId(deviceZt.getFkId());

                DrainMsgNotice notice  = drainMsgNoticeService.sendMsgNotice(noticeBo,paramMap);
                userIdList.add(sysUser.getId());

                //5、发送短信通知
                //是否l发送短信（1=是 0=否）
                String ruleVoSendSms  = ruleVo.getSendMessage();
                if("1".equals(ruleVoSendSms))
                {
                    String smsMsg = notice.getNoticeVal();
                    String templateId="";
                    LinkedHashMap<String, String> smsMap  = new LinkedHashMap<>();
                    smsMap.put("smsMsg",smsMsg);
                    //调用第三方接口发送短信
                    drainSmsInfoService.sendSmsInfo(sysUser.getPhonenumber(),"2",smsMsg,templateId,smsMap);

                }

            }

        }

        return  userIdList;
    }

}
